"""
回测服务 v0.0.9
基于增量数据获取和缓存的滑动窗口回测算法
"""

from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
from ..services.binance_client import BinanceDataClient, SUPPORTED_INTERVALS
from ..services.chart_service import ChartService
from ..services.ai_strategy_service import AIStrategyService
from ..services.kline_cache_service import KlineCacheService
from ..services.indicators import calculate_ema, calculate_macd, calculate_atr
from ..config import config


class BacktestingServiceV9:
    """回测服务 v0.0.9"""

    def __init__(self) -> None:
        """初始化回测服务"""
        self.binance_client = BinanceDataClient()
        self.chart_service = ChartService()
        self.ai_service = AIStrategyService()
        self.cache_service = KlineCacheService()

    def _is_uptrend(self, klines: List[Dict], period: int = 5) -> bool:
        """
        判断是否为上升趋势
        简化为检查最近N根K线的收盘价是否递增

        Args:
            klines: K线数据
            period: 观察周期，默认5

        Returns:
            是否为上升趋势
        """
        if len(klines) < period:
            return False

        # 检查最近period根K线的收盘价趋势
        recent_closes = [k['close'] for k in klines[-period:]]

        # 简单判断：至少有60%的K线是上涨的
        up_count = sum(1 for i in range(1, len(recent_closes)) if recent_closes[i] > recent_closes[i-1])
        return up_count >= (period - 1) * 0.6

    def _is_downtrend(self, klines: List[Dict], period: int = 5) -> bool:
        """
        判断是否为下降趋势

        Args:
            klines: K线数据
            period: 观察周期，默认5

        Returns:
            是否为下降趋势
        """
        if len(klines) < period:
            return False

        recent_closes = [k['close'] for k in klines[-period:]]

        down_count = sum(1 for i in range(1, len(recent_closes)) if recent_closes[i] < recent_closes[i-1])
        return down_count >= (period - 1) * 0.6

    def _is_sideways_market(self, klines: List[Dict], period: int = 10) -> bool:
        """
        判断是否为震荡市场（箱体行情）
        通过价格波动范围来判断

        Args:
            klines: K线数据
            period: 观察周期，默认10

        Returns:
            是否为震荡市场
        """
        if len(klines) < period:
            return False

        recent_klines = klines[-period:]
        highs = [k['high'] for k in recent_klines]
        lows = [k['low'] for k in recent_klines]

        max_high = max(highs)
        min_low = min(lows)
        range_pct = (max_high - min_low) / min_low

        # 波动范围小于2%认为是震荡
        return range_pct < 0.02

    def _is_trend_exhausted(self, klines: List[Dict], action: str) -> bool:
        """
        判断趋势是否衰竭（趋势末段）
        Al Brooks理论：趋势延续两轮后应谨慎

        Args:
            klines: K线数据
            action: 交易方向 ('long' or 'short')

        Returns:
            趋势是否衰竭
        """
        if len(klines) < 10:
            return False

        # 获取最近10根K线的收盘价
        recent_closes = [k['close'] for k in klines[-10:]]

        # 简化判断：检查最近的上涨/下跌是否减弱
        if action in ['long', 'Long', 'LONG']:
            # 计算最近5次上涨的幅度
            up_moves = []
            for i in range(1, len(recent_closes)):
                if recent_closes[i] > recent_closes[i-1]:
                    up_moves.append(recent_closes[i] - recent_closes[i-1])

            # 如果最近3次上涨幅度逐渐减小，可能趋势衰竭
            if len(up_moves) >= 3:
                recent_up_moves = up_moves[-3:]
                return recent_up_moves[0] > recent_up_moves[1] > recent_up_moves[2]

        elif action in ['short', 'Short', 'SHORT']:
            # 计算最近5次下跌的幅度
            down_moves = []
            for i in range(1, len(recent_closes)):
                if recent_closes[i] < recent_closes[i-1]:
                    down_moves.append(recent_closes[i-1] - recent_closes[i])

            if len(down_moves) >= 3:
                recent_down_moves = down_moves[-3:]
                return recent_down_moves[0] > recent_down_moves[1] > recent_down_moves[2]

        return False

    def _is_wedge_reversal(self, klines: List[Dict], action: str) -> bool:
        """
        检测楔形(wedge)三推反转形态
        Al Brooks理论中的楔形反转信号

        Args:
            klines: K线数据
            action: 交易方向

        Returns:
            是否检测到楔形反转
        """
        if len(klines) < 15:
            return False

        # 获取最近15根K线的高点和低点
        highs = []
        lows = []
        for i in range(5, len(klines[-15:])):
            idx = len(klines) - 15 + i
            highs.append(klines[idx]['high'])
            lows.append(klines[idx]['low'])

        # 检查趋势线收敛（楔形特征）
        # 上升楔形：高点递增速度放缓 + 低点递增速度加快
        # 下降楔形：高点递减速度加快 + 低点递减速度放缓

        if action in ['long', 'Long', 'LONG']:
            # 检查下降楔形（可能反转向上）
            if len(highs) >= 5 and len(lows) >= 5:
                # 简化判断：高点和低点都在收敛
                high_trend = (highs[-1] - highs[-5]) / 5
                low_trend = (lows[-1] - lows[-5]) / 5
                # 高点递减，低点递减但速度放缓
                return high_trend < 0 and low_trend < 0 and abs(low_trend) < abs(high_trend)

        elif action in ['short', 'Short', 'SHORT']:
            # 检查上升楔形（可能反转向下）
            if len(highs) >= 5 and len(lows) >= 5:
                high_trend = (highs[-1] - highs[-5]) / 5
                low_trend = (lows[-1] - lows[-5]) / 5
                # 高点递增但速度放缓，低点递增
                return high_trend > 0 and low_trend > 0 and high_trend < low_trend

        return False

    def _is_sudden_move_reversal(self, klines: List[Dict], action: str) -> bool:
        """
        检测急跌/急涨后的反弹
        Al Brooks理论：急跌/急涨大概率引发反弹

        Args:
            klines: K线数据
            action: 交易方向

        Returns:
            是否检测到急跌/急涨后的反弹风险
        """
        if len(klines) < 3:
            return False

        # 获取最近3根K线
        kline_n2 = klines[-3]  # K-2
        kline_n1 = klines[-2]  # K-1
        kline_n = klines[-1]   # K

        # 计算价格变化幅度（百分比）
        change_n1 = (kline_n1['close'] - kline_n2['close']) / kline_n2['close']
        change_n = (kline_n['close'] - kline_n1['close']) / kline_n1['close']

        if action in ['long', 'Long', 'LONG']:
            # 做多时，检查是否急跌后可能反弹（避免抄底）
            # 连续两根大阴线（跌幅>1%）
            return change_n1 < -0.01 and change_n < -0.01

        elif action in ['short', 'Short', 'SHORT']:
            # 做空时，检查是否急涨后可能反弹（避免追高）
            # 连续两根大阳线（涨幅>1%）
            return change_n1 > 0.01 and change_n > 0.01

        return False

    def _should_avoid_trade(self, historical_data: List[Dict], action: str, breakout_price: Optional[float] = None) -> Tuple[bool, str]:
        """
        综合判断是否应该避免交易（避免大亏损）
        PRD v0.3.7：努力避免大亏损的情况

        Args:
            historical_data: 历史K线数据
            action: 交易方向
            breakout_price: 枢轴点计算的突破价格（可选）

        Returns:
            (是否应该避免, 原因)
        """
        current_kline = historical_data[-1]
        current_price = current_kline['close']
        prev_price = historical_data[-2]['close'] if len(historical_data) > 1 else current_price

        # 检查0: PRD v0.3.7新增 - 突破确认机制
        # 开仓时必须确认当前K线是否穿过breakoutPrice
        if breakout_price is not None and action in ['long', 'Long', 'LONG', 'short', 'Short', 'SHORT']:
            if action in ['long', 'Long', 'LONG']:
                # 做long：检查当前K线最高价是否≥breakoutPrice（确认向上突破）
                current_high = current_kline['high']
                if current_high < breakout_price:
                    return True, f"未确认突破：当前最高价{current_high:.2f} < breakoutPrice{breakout_price:.2f}，未向上突破"
            elif action in ['short', 'Short', 'SHORT']:
                # 做short：检查当前K线最低价是否≤breakoutPrice（确认向下突破）
                current_low = current_kline['low']
                if current_low > breakout_price:
                    return True, f"未确认突破：当前最低价{current_low:.2f} > breakoutPrice{breakout_price:.2f}，未向下突破"

        # 检查1: 避免逆势开仓
        # 不在当日K线下跌时做多，不在当日K线上涨时做空
        if action in ['long', 'Long', 'LONG']:
            if current_price < prev_price:
                return True, "避免逆势：当日K线下跌，不做多"
        elif action in ['short', 'Short', 'SHORT']:
            if current_price > prev_price:
                return True, "避免逆势：当日K线上涨，不做空"

        # 检查2: 避免震荡市交易
        if self._is_sideways_market(historical_data):
            return True, "避免震荡市：当前为箱体行情"

        # 检查3: 避免趋势末段交易
        if self._is_trend_exhausted(historical_data, action):
            return True, "避免趋势末段：趋势动能衰竭"

        # 检查4: 避免楔形反转陷阱
        if self._is_wedge_reversal(historical_data, action):
            return True, "避免楔形反转：检测到楔形反转形态"

        # 检查5: 避免急跌/急涨反弹
        if self._is_sudden_move_reversal(historical_data, action):
            return True, "避免急跌急涨反弹：检测到急跌/急涨信号"

        # 检查6: 确保趋势方向正确
        if action in ['long', 'Long', 'LONG']:
            if not self._is_uptrend(historical_data):
                return True, "避免逆趋势做多：当前非上升趋势"
        elif action in ['short', 'Short', 'SHORT']:
            if not self._is_downtrend(historical_data):
                return True, "避免逆趋势做空：当前非下降趋势"

        return False, "可以开仓"

    def run_backtesting(
        self,
        symbol: str,
        start_time: str,
        end_time: str,
        interval: SUPPORTED_INTERVALS = '15m',
        profitStop: float = 20.0,
        enableTrendReversal: bool = True,
        enableDrawdownProtection: bool = True,
        enableSmartTrailing: bool = True,
        reversalSensitivity: str = 'medium'
    ) -> Dict:
        """
        运行回测 v0.2.6（支持分钟级别时间参数 + 趋势反转检测）

        Args:
            symbol: 交易对符号
            start_time: 开始时间 (支持格式: YYYY-MM-DD 或 YYYY-MM-DD HH:MM)
            end_time: 结束时间 (支持格式: YYYY-MM-DD 或 YYYY-MM-DD HH:MM)
            interval: 时间周期
            profitStop: 移动止盈触发百分比（默认20%，盈利达到此比例时激活移动止盈）
            enableTrendReversal: 是否启用趋势反转检测（默认True）
            enableDrawdownProtection: 是否启用动态回撤保护（默认True）
            enableSmartTrailing: 是否启用智能移动止损（默认True）
            reversalSensitivity: 反转检测灵敏度 ('low', 'medium', 'high')

        Returns:
            回测结果

        Note:
            v0.2.6: 新增趋势反转检测、动态回撤保护、智能移动止损
            v0.1.9: 新增支持分钟级别的时间参数，可精确回测几小时内的数据
            示例:
                - start_time="2024-01-01", end_time="2024-01-01" (回测整天)
                - start_time="2024-01-01 09:00", end_time="2024-01-01 12:00" (回测3小时)
        """
        try:
            # 1. 解析时间（支持分钟级别）
            # 尝试多种时间格式
            time_formats = [
                '%Y-%m-%d %H:%M:%S',  # 完整日期时间
                '%Y-%m-%d %H:%M',     # 简化日期时间
                '%Y-%m-%d'            # 仅日期（向后兼容）
            ]

            start_dt = None
            end_dt = None

            # 解析开始时间
            for fmt in time_formats:
                try:
                    start_dt = datetime.strptime(start_time, fmt)
                    break
                except ValueError:
                    continue

            if start_dt is None:
                raise ValueError(f"开始时间格式无效: {start_time}，支持格式：YYYY-MM-DD 或 YYYY-MM-DD HH:MM")

            # 解析结束时间
            for fmt in time_formats:
                try:
                    end_dt = datetime.strptime(end_time, fmt)
                    break
                except ValueError:
                    continue

            if end_dt is None:
                raise ValueError(f"结束时间格式无效: {end_time}，支持格式：YYYY-MM-DD 或 YYYY-MM-DD HH:MM")

            # v0.1.9优化：智能处理时间范围
            # 重要：先记录原始日期和原始结束时间
            start_date = start_dt.date()
            end_date_original = end_dt.date()
            end_time_provided = end_dt.time()
            start_time_provided = start_dt.time()

            # 如果用户提供了具体时间（不是仅日期），则使用该时间
            if end_time_provided != datetime.min.time():
                # 用户提供了具体时间，直接使用
                pass
            else:
                # 用户只提供了日期，需要扩展
                if start_date == end_date_original:
                    # 同一天：扩展到24小时（从00:00到次日00:00）
                    end_dt = end_dt + timedelta(hours=24)
                else:
                    # 跨天：扩展到次日00:00，确保包含最后一天的完整数据
                    # 例如：2025-06-01到2025-06-11 = 从06-01 00:00到06-12 00:00（包含06-11的完整数据）
                    end_dt = end_dt + timedelta(days=1)

            # 如果开始时间也仅有日期（没有时分秒），则设置为00:00:00
            if start_time_provided == datetime.min.time():
                start_dt = datetime.combine(start_date, datetime.min.time())

            # 2. 使用增量数据获取
            klines = self._get_incremental_klines(
                symbol=symbol,
                start_time=start_dt,
                end_time=end_dt,
                interval=interval
            )

            if not klines:
                raise ValueError(f"未获取到 {symbol} 在 {start_time} 到 {end_time} 期间的K线数据")

            # 3. 执行回测逻辑
            trades, analysis_count, analyses = self._execute_backtesting_v9(
                symbol, klines, interval, start_dt, profitStop,
                enableTrendReversal, enableDrawdownProtection,
                enableSmartTrailing, reversalSensitivity
            )

            # 4. 计算总盈亏
            total_profit = sum(trade['profit'] for trade in trades)

            return {
                'code': 200,
                'data': {
                    'version': 'v0.0.9',
                    'interval': interval,
                    'symbol': symbol,
                    'trades': trades,
                    'totalProfitUsdt': int(total_profit),
                    'analysisCount': analysis_count,
                    'analyses': analyses  # v0.1.1新增：AI分析详情
                },
                'msg': 'success'
            }

        except Exception as e:
            return {
                'code': 500,
                'data': {},
                'msg': f'回测失败: {str(e)}'
            }

    def _get_incremental_klines(
        self,
        symbol: str,
        start_time: datetime,
        end_time: datetime,
        interval: str
    ) -> List[Dict]:
        """
        一次性获取所有K线数据（v0.1.4优化）
        减少API请求：只请求一次，然后从CSV逐行读取分析

        Args:
            symbol: 交易对符号
            start_time: 开始时间
            end_time: 结束时间
            interval: 时间周期

        Returns:
            完整的K线数据列表
        """
        # 1. 清理旧缓存
        self.cache_service.clear_cache(symbol, start_time, end_time)

        # 2. 一次性获取所有数据
        print(f"一次性获取数据: {start_time} 到 {end_time}")
        klines = self.binance_client.get_klines(
            symbol=symbol,
            interval=interval,  # type: ignore
            start_time=start_time,
            end_time=end_time,
            limit=1500
        )

        if klines:
            # 缓存所有数据到CSV
            self.cache_service.write_cache(symbol, klines, start_time, end_time, append=False)
            print(f"数据获取完成: 总计 {len(klines)} 根K线，已缓存到CSV")
        else:
            print("警告：未获取到任何数据")

        return klines

    def _get_interval_delta(self, interval: str) -> timedelta:
        """获取时间间隔对应的timedelta"""
        if interval == '5m':
            return timedelta(minutes=5)
        elif interval == '1h':
            return timedelta(hours=1)
        elif interval == '4h':
            return timedelta(hours=4)
        else:
            raise ValueError(f"不支持的时间间隔: {interval}")

    def _execute_backtesting_v9(
        self,
        symbol: str,
        klines: List[Dict],
        interval: str,
        start_dt: datetime,
        profitStop: float,
        enableTrendReversal: bool,
        enableDrawdownProtection: bool,
        enableSmartTrailing: bool,
        reversalSensitivity: str
    ) -> Tuple[List[Dict], int, List[Dict]]:
        """
        执行v0.2.6回测逻辑（支持趋势反转检测）

        Args:
            symbol: 交易对符号
            klines: K线数据
            interval: 时间周期
            start_dt: 开始时间
            profitStop: 移动止盈触发百分比
            enableTrendReversal: 是否启用趋势反转检测
            enableDrawdownProtection: 是否启用动态回撤保护
            enableSmartTrailing: 是否启用智能移动止损
            reversalSensitivity: 反转检测灵敏度

        Returns:
            (交易记录列表, 分析次数, AI分析详情列表)
        """
        trades = []
        position = None  # 当前持仓
        analysis_count = 0  # 分析次数
        analyses = []  # 存储每次AI分析的结果

        # 步骤1: 验证数据
        if len(klines) < 9:
            raise ValueError("回测数据不足，需要至少9小时的数据")

        # 步骤2: 将完整数据写入缓存（使用固定文件名，避免时间范围导致的缓存miss）
        # 这样可以确保在滑动窗口回测中缓存能够命中
        self.cache_service.write_cache(
            symbol=symbol,
            data=klines,
            append=False  # 覆盖模式
        )

        # 步骤3: 逐根K线进行递进分析（v0.1.4优化）
        # 注意：klines长度应该足够长（>10），从第9根开始分析
        for i in range(9, len(klines)):
            print(f"[DEBUG v0.3.5] 开始处理第{i}条K线")
            current_kline = klines[i]

            # v0.1.4优化：逐行分析 - 读取前i+1行数据
            # 第1次(i=9)：读取前9行
            # 第2次(i=10)：读取前10行
            # 第3次(i=11)：读取前11行
            # 使用固定文件名查询，然后通过limit_rows限制数据量
            historical_data = self.cache_service.get_cached_data_in_range(
                symbol=symbol,
                start_time=None,  # 不指定时间范围，使用固定文件
                end_time=None,    # 不指定时间范围，使用固定文件
                limit_rows=i + 1  # v0.1.4核心：逐行递增分析
            )

            if not historical_data:
                print(f"警告：未找到缓存数据，使用内存数据")
                historical_data = klines[:i+1]

            # 生成图表（使用回测开始时间）
            # DEBUG: 添加调试日志，检查interval参数
            # 修复：使用open_time而不是close_time，确保图表时间范围与K线日期一致
            print(f"[DEBUG] 生成图表: interval={interval}, symbol={symbol}, 时间范围: {start_dt} - {datetime.fromtimestamp(current_kline['open_time'] / 1000)}")
            chart_path = self.chart_service.generate_chart_with_time_range(
                symbol=symbol,
                klines_data=historical_data,
                start_time=start_dt,  # 使用回测开始时间
                end_time=datetime.fromtimestamp(current_kline['open_time'] / 1000),
                interval=interval,
                chart_type='candlestick',
                show_volume=True
            )

            # 获取AI分析（将图表路径和数据传给AI服务，避免重复生成图表）
            # v0.1.8: 传入当前持仓信息，让AI知道是否已有仓位
            result = self.ai_service.analyze_klines_with_ai(
                symbol=symbol,
                interval=interval,  # type: ignore
                limit=len(historical_data),
                chart_type='candlestick',
                existing_chart_path=chart_path,
                klines_data=historical_data,
                current_position=position  # 传入当前持仓状态
            )

            analysis_count += 1

            # 记录AI分析结果（避免重复时间戳）
            # Bugfix v0.3.3修复 + Bugfix v0.3.4保持：使用open_time确保日期正确
            kline_time = current_kline['open_time']
            current_time = datetime.fromtimestamp(kline_time / 1000)

            # 提取AI分析结果
            ai_analysis = result.get('data', {}).get('analysis', {})
            action = ai_analysis.get('action', 'hold')
            reason = ai_analysis.get('reason', '无分析')
            stop_loss = ai_analysis.get('stopLoss', None)
            take_profit = ai_analysis.get('takeProfit', None)
            measure_move = ai_analysis.get('measureMove', None)
            ai_open_price = ai_analysis.get('open_price',None)
            ai_close_price = ai_analysis.get('close_price',None)

            # PRD v0.3.6: 使用枢轴点算法计算breakoutPrice，不再依赖AI识别
            # 枢轴点算法：交易员常用的专业工具
            # 中心枢轴点 (P) = (High + Low + Close) / 3
            # 第一支撑 (S1) = (P * 2) - High
            # 第一压力 (R1) = (P * 2) - Low

            # 初始化枢轴点相关变量
            pivot_point = None
            s1 = None
            r1 = None
            breakout_price = None

            # PRD v0.3.7优化：确保breakoutPrice只使用当前K线之前的数据
            # 根据PRD v0.3.6：breakoutPrice对于做多就是前期压力位，对于做空就是前期支撑位
            if len(historical_data) > 1:
                # 使用historical_data[:-1]作为基准数据（排除当前K线）
                base_data = historical_data[:-1]

                # 计算基准期间的高、低、收
                prev_high = max(k['high'] for k in base_data)
                prev_low = min(k['low'] for k in base_data)
                prev_close = base_data[-1]['close']

                # 简化的枢轴点算法：直接使用前期高/低作为突破价格
                # 避免过于严格的R1/S1计算，使用更直接的方法
                # 做多：使用prev_high * 0.998（前期压力位稍微下调0.2%，更容易突破）
                # 做空：使用prev_low * 1.002（前期支撑位稍微上调0.2%，更容易跌破）
                if action in ['long', 'Long', 'LONG']:
                    # 前期压力位做多突破
                    breakout_price = prev_high * 0.998
                elif action in ['short', 'Short', 'SHORT']:
                    # 前期支撑位做空突破
                    breakout_price = prev_low * 1.002
                else:
                    breakout_price = None

                # 同时计算枢轴点用于止盈止损（保留原有算法）
                pivot_point = (prev_high + prev_low + prev_close) / 3
                s1 = (pivot_point * 2) - prev_high
                r1 = (pivot_point * 2) - prev_low

                # DEBUG: 打印枢轴点计算的breakoutPrice（显示数据范围）
                r1_str = f"{r1:.2f}" if r1 is not None else "N/A"
                s1_str = f"{s1:.2f}" if s1 is not None else "N/A"
                p_str = f"{pivot_point:.2f}" if pivot_point is not None else "N/A"
                print(f"[DEBUG PRD v0.3.6] 枢轴点算法计算breakoutPrice: {breakout_price}")
                print(f"  排除当前K线后的历史数据: {len(base_data)}条 (原始数据:{len(historical_data)}条)")
                print(f"  基准数据: High={prev_high:.2f}, Low={prev_low:.2f}, Close={prev_close:.2f}")
                print(f"  枢轴点水平: P={p_str}, S1={s1_str}, R1={r1_str}")
            else:
                # 数据不足时使用传统方法（但要排除当前K线）
                # PRD v0.3.7第5个需求：确保breakoutPrice只使用当前K线之前的数据
                # 使用historical_data[:-1]排除当前K线
                base_data_for_traditional = historical_data[:-1]
                historical_prices = [k['high'] for k in base_data_for_traditional[-5:]]
                breakout_price = max(historical_prices) if historical_prices else None
                print(f"[DEBUG PRD v0.3.6] 数据不足，使用传统方法（排除当前K线）: {breakout_price}")
                print(f"  排除当前K线后的历史数据: {len(base_data_for_traditional)}条 (原始数据:{len(historical_data)}条)")
                print(f"  使用最近5条历史数据的高价: {historical_prices}")

            # PRD v0.3.6: 基于枢轴点重新计算止盈止损价格
            # 由于breakoutPrice使用枢轴点，AI建议的stopLoss/takeProfit/measureMove也需要相应调整
            if pivot_point is not None and breakout_price is not None:
                # 计算枢轴点衍生水平
                # 第二支撑 S2 = P - (High - Low)
                s2 = pivot_point - (prev_high - prev_low)
                # 第二压力 R2 = P + (High - Low)
                r2 = pivot_point + (prev_high - prev_low)

                # 前期波动区间距离
                range_distance = prev_high - prev_low

                # 基于枢轴点和breakoutPrice重新计算measureMove
                # measureMove = 突破点 ± 前期波动区间距离
                if action in ['long', 'Long', 'LONG']:
                    # 做多：measureMove = breakoutPrice (R1) + 区间距离
                    recalculated_measure_move = breakout_price + range_distance
                    # 重新计算stopLoss（基于S1）
                    recalculated_stop_loss = s1
                    # 重新计算takeProfit（基于R2）
                    recalculated_take_profit = r2
                elif action in ['short', 'Short', 'SHORT']:
                    # 做空：measureMove = breakoutPrice (S1) - 区间距离
                    recalculated_measure_move = breakout_price - range_distance
                    # 重新计算stopLoss（基于R1）
                    recalculated_stop_loss = r1
                    # 重新计算takeProfit（基于S2）
                    recalculated_take_profit = s2
                else:
                    # 其他action使用AI建议
                    recalculated_measure_move = measure_move
                    recalculated_stop_loss = stop_loss
                    recalculated_take_profit = take_profit

                # 使用重新计算的价格覆盖AI建议（确保枢轴点一致性）
                measure_move = recalculated_measure_move
                stop_loss = recalculated_stop_loss
                take_profit = recalculated_take_profit

                # DEBUG: 打印重新计算的止盈止损
                sl_str = f"{stop_loss:.2f}" if stop_loss is not None else "N/A"
                tp_str = f"{take_profit:.2f}" if take_profit is not None else "N/A"
                mm_str = f"{measure_move:.2f}" if measure_move is not None else "N/A"
                print(f"[DEBUG PRD v0.3.6] 基于枢轴点重新计算: stopLoss={sl_str}, takeProfit={tp_str}, measureMove={mm_str}")

                p2_str = f"{pivot_point:.2f}" if pivot_point is not None else "N/A"
                s1_2_str = f"{s1:.2f}" if s1 is not None else "N/A"
                s2_str = f"{s2:.2f}" if s2 is not None else "N/A"
                r1_2_str = f"{r1:.2f}" if r1 is not None else "N/A"
                r2_str = f"{r2:.2f}" if r2 is not None else "N/A"
                print(f"  枢轴点水平: P={p2_str}, S1={s1_2_str}, S2={s2_str}, R1={r1_2_str}, R2={r2_str}")
            else:
                print(f"[DEBUG PRD v0.3.6] 使用AI建议的止盈止损: stopLoss={stop_loss}, takeProfit={take_profit}, measureMove={measure_move}")

            # v0.2.9: 新增字段
            support_resistance_level = ai_analysis.get('supportResistanceLevel', None)

            # Bugfix v0.3.4: 初始化平仓标志（避免变量未定义错误）
            should_close_by_ai_price = False  # 默认为False，无持仓时不会触发平仓

            # 执行做空/做多双向交易逻辑（注意：action已经在第319行提取过了）
            if result['code'] == 200:
                if position is None:  # 无持仓
                    # PRD v0.3.7: 防亏损检查（包括突破确认）
                    # 只有在Action为long或short时才进行防亏损检查
                    if action in ['long', 'Long', 'LONG', 'short', 'Short', 'SHORT']:
                        should_avoid, avoid_reason = self._should_avoid_trade(historical_data, action, breakout_price)
                        if should_avoid:
                            print(f"[DEBUG PRD v0.3.7] 避免交易: {avoid_reason}")
                            action = 'hold'  # 将action改为hold，避免开仓
                            reason = f"{reason} | {avoid_reason}"

                    # 执行开仓逻辑
                    if action in ['long', 'Long', 'LONG']:
                        # 开仓做多
                        # v0.2.9优化：如果有突破价，使用突破价作为开仓价；否则使用收盘价
                        # 这里使用breakout_price在实盘有事后诸葛亮的意思，行情走完后分析，然后回到breakout_price入场
                        #open_price = breakout_price if breakout_price is not None else current_kline['close']
                        open_price = current_kline['close']
                        position = {
                            'action': 'long',
                            'position_type': 'long',  # 多头
                            'open_time': current_kline['open_time'],  # Bugfix v0.3.4: 使用开盘时间与analyses时间保持一致
                            'open_price': open_price,  # v0.2.9：使用突破价或收盘价
                            'open_index': i,
                            'highest_price': open_price,  # 记录最高价
                            'lowest_price': open_price,   # 记录最低价
                            'profitStop': profitStop,  # 新增：移动止盈触发百分比
                            # 保存开仓时AI建议的价格（v0.2.8修复）
                            'stopLoss': stop_loss,
                            'takeProfit': take_profit,
                            'measureMove': measure_move,
                            # PRD v0.3.6: 本地计算breakoutPrice
                            'breakoutPrice': breakout_price,
                            'supportResistanceLevel': support_resistance_level
                        }

                        # DEBUG: 打印开仓时保存的AI价格建议（v0.2.8验证）
                        price_source = "突破价" if breakout_price is not None else "收盘价"
                        print(f"[DEBUG v0.2.8] 开仓: LONG @{open_price}({price_source}), 本地计算breakoutPrice={breakout_price}, AI建议: stopLoss={stop_loss}, takeProfit={take_profit}, measureMove={measure_move}")
                    elif action in ['short', 'Short', 'SHORT']:
                        # 开仓做空
                        # v0.2.9优化：如果有跌破价（突破价），使用跌破价作为开仓价；否则使用收盘价
                        #open_price = breakout_price if breakout_price is not None else current_kline['close']
                        open_price = current_kline['close']
                        position = {
                            'action': 'short',
                            'position_type': 'short',  # 空头
                            'open_time': current_kline['open_time'],  # Bugfix v0.3.4: 使用开盘时间与analyses时间保持一致
                            'open_price': open_price,  # v0.2.9：使用突破价或收盘价
                            'open_index': i,
                            'highest_price': open_price,  # 记录最高价
                            'lowest_price': open_price,   # 记录最低价
                            'profitStop': profitStop,  # 新增：移动止盈触发百分比
                            # 保存开仓时AI建议的价格（v0.2.8修复）
                            'stopLoss': stop_loss,
                            'takeProfit': take_profit,
                            'measureMove': measure_move,
                            # PRD v0.3.6: 本地计算breakoutPrice
                            'breakoutPrice': breakout_price,
                            'supportResistanceLevel': support_resistance_level
                        }

                        # DEBUG: 打印开仓时保存的AI价格建议（v0.2.8验证）
                        price_source = "突破价" if breakout_price is not None else "收盘价"
                        print(f"[DEBUG v0.2.8] 开仓: SHORT @{open_price}({price_source}), 本地计算breakoutPrice={breakout_price}, AI建议: stopLoss={stop_loss}, takeProfit={take_profit}, measureMove={measure_move}")
                    # hold/close时不操作
                else:  # 有持仓
                    # 更新最高价和最低价（持仓期间记录极值）
                    position['highest_price'] = max(position['highest_price'], current_kline['high'])
                    position['lowest_price'] = min(position['lowest_price'], current_kline['low'])

                    # 获取AI价格建议（用于止盈止损）
                    # v0.2.8修复：使用开仓时保存的AI价格建议，而不是当前分析的建议
                    # 这样当价格触及开仓时AI建议的目标位时，系统能正确止盈
                    position_measure_move = position.get('measureMove', None)
                    position_take_profit = position.get('takeProfit', None)
                    position_stop_loss = position.get('stopLoss', None)

                    # 检查是否触发AI建议的止盈价格
                    current_price = current_kline['close']
                    current_position_type = position.get('position_type', 'long')
                    should_close_by_ai_price = False
                    exit_reason = None

                    # DEBUG: 添加调试信息（监控所有持仓情况）
                    if position is not None:
                        print(f"[DEBUG v0.2.8 AI止盈] index={i}, position_type={current_position_type}, price={current_price}")
                        print(f"  开仓时AI建议: stopLoss={position_stop_loss}, takeProfit={position_take_profit}, measureMove={position_measure_move}")
                        print(f"  当前分析: stopLoss={ai_analysis.get('stopLoss')}, takeProfit={ai_analysis.get('takeProfit')}, measureMove={ai_analysis.get('measureMove')}")

                    # 基于AI价格的止盈检查（PRD v0.3.4修复：使用当日最高/最低价而非收盘价）
                    if current_position_type == 'short':
                        # 做空时，价格下跌到止盈价格
                        # 优先检查止损位（v0.2.9：触及止损用止损价平仓）
                        if position_stop_loss is not None and current_price >= position_stop_loss:
                            should_close_by_ai_price = True
                            exit_reason = "止损"
                            print(f"[DEBUG v0.2.9] 触发止损: {current_price} >= {position_stop_loss} (开仓建议)")
                        # 再检查止盈位（修复：使用当日最低价）
                        elif position_take_profit is not None and position['lowest_price'] <= position_take_profit:
                            should_close_by_ai_price = True
                            exit_reason = "止盈-takeProfit"
                            print(f"[DEBUG v0.3.4] 触发止盈-takeProfit: 当日最低价{position['lowest_price']} <= {position_take_profit} (开仓建议)")
                        elif position_measure_move is not None and position['lowest_price'] <= position_measure_move:
                            should_close_by_ai_price = True
                            exit_reason = "止盈-measureMove"
                            print(f"[DEBUG v0.3.4] 触发止盈-measureMove: 当日最低价{position['lowest_price']} <= {position_measure_move} (开仓建议)")
                    elif current_position_type == 'long':
                        # 做多时，价格上涨到止盈价格
                        # 优先检查止损位（v0.2.9：触及止损用止损价平仓）
                        if position_stop_loss is not None and current_price <= position_stop_loss:
                            should_close_by_ai_price = True
                            exit_reason = "止损"
                            print(f"[DEBUG v0.2.9] 触发止损: {current_price} <= {position_stop_loss} (开仓建议)")
                        # 再检查止盈位（修复：使用当日最高价）
                        elif position_take_profit is not None and position['highest_price'] >= position_take_profit:
                            should_close_by_ai_price = True
                            exit_reason = "止盈-takeProfit"
                            print(f"[DEBUG v0.3.4] 触发止盈-takeProfit: 当日最高价{position['highest_price']} >= {position_take_profit} (开仓建议)")
                        elif position_measure_move is not None and position['highest_price'] >= position_measure_move:
                            should_close_by_ai_price = True
                            exit_reason = "止盈-measureMove"
                            print(f"[DEBUG v0.3.4] 触发止盈-measureMove: 当日最高价{position['highest_price']} >= {position_measure_move} (开仓建议)")

                    # 如果触发AI价格止盈，立即执行平仓
                    if should_close_by_ai_price:
                        # 平仓操作
                        # Bugfix v0.3.5: 使用close_time确保period时间范围正确（开仓用open_time，平仓用close_time）
                        position['close_time'] = current_kline['open_time']
                        # v0.2.9: 根据平仓原因选择平仓价
                        if exit_reason == "止损":
                            # 止损时使用止损价作为平仓价
                            position['close_price'] = position_stop_loss
                            print(f"[DEBUG v0.2.9] 止损平仓: 使用止损价 {position_stop_loss}")
                        else:
                            # 止盈时使用收盘价
                            position['close_price'] = current_kline['close']
                        position['close_index'] = i

                        # 计算盈亏
                        if current_position_type == 'long':
                            profit = position['close_price'] - position['open_price']
                            max_profit = position['highest_price'] - position['open_price']
                            max_loss = position['open_price'] - position['lowest_price']
                        else:  # short
                            profit = position['open_price'] - position['close_price']
                            max_profit = position['open_price'] - position['lowest_price']
                            max_loss = position['highest_price'] - position['open_price']

                        # 计算盈亏比
                        # v0.3.0修复：避免Infinity，改用大数值9999.99
                        if max_loss > 0:
                            profit_ratio = round(abs(max_profit / max_loss), 2)
                        else:
                            profit_ratio = 9999.99 if max_profit > 0 else 0

                        # 格式化交易周期
                        period = self._format_period(
                            position['open_time'],
                            position['close_time']
                        )

                        # 添加到交易记录
                        trades.append({
                            'action': current_position_type,
                            'position_type': current_position_type,
                            'period': period,
                            'profit': round(profit, 2),
                            'openPrice': position['open_price'],
                            'closePrice': position['close_price'],
                            'exitReason': exit_reason,  # 使用AI建议的止盈原因
                            'profitRatio': profit_ratio
                        })

                        position = None  # 清空持仓
                    else:
                        # 没有触发AI价格止盈，继续原有逻辑
                        # 根据持仓类型和信号决定操作
                        if current_position_type == 'long':  # 当前是多头持仓
                            if action in ['close', 'Close', 'CLOSE', 'short', 'Short', 'SHORT']:
                                # 平多头
                                # Bugfix v0.3.5: 使用close_time确保period时间范围正确（开仓用open_time，平仓用close_time）
                                position['close_time'] = current_kline['open_time']
                                position['close_price'] = current_kline['close']
                                position['close_index'] = i

                                # 计算盈亏比和离场原因
                                profit = position['close_price'] - position['open_price']

                                # 计算最大盈利和最大亏损（用于盈亏比）
                                max_profit = position['highest_price'] - position['open_price']
                                max_loss = position['open_price'] - position['lowest_price']

                                # 计算盈亏比（盈利/亏损的比值，避免除零）
                                # v0.3.0修复：避免Infinity，改用大数值9999.99
                                if max_loss > 0:
                                    profit_ratio = round(abs(max_profit / max_loss), 2)
                                else:
                                    profit_ratio = 9999.99 if max_profit > 0 else 0

                                # 判断离场原因（基于最终盈亏方向）
                                exit_reason = "止盈" if profit > 0 else "止损"

                                period = self._format_period(
                                    position['open_time'],
                                    position['close_time']
                                )

                                trades.append({
                                    'action': 'long',  # 记录为long表示多头交易
                                    'position_type': 'long',
                                    'period': period,
                                    'profit': round(profit, 2),
                                    'openPrice': position['open_price'],
                                    'closePrice': position['close_price'],
                                    'exitReason': exit_reason,  # 离场原因
                                    'profitRatio': profit_ratio  # 盈亏比
                                })

                                position = None  # 清空持仓
                        # long/hold时继续持有
                        elif current_position_type == 'short':  # 当前是空头持仓
                            if action in ['close', 'Close', 'CLOSE', 'long', 'Long', 'LONG']:
                                # 平空头
                                # Bugfix v0.3.5: 使用close_time确保period时间范围正确（开仓用open_time，平仓用close_time）
                                position['close_time'] = current_kline['close_time']
                                position['close_price'] = current_kline['close']
                                position['close_index'] = i

                                # 计算空头盈亏：开仓价 - 平仓价
                                profit = position['open_price'] - position['close_price']

                                # 计算最大盈利和最大亏损（做空相反）
                                max_profit = position['open_price'] - position['lowest_price']
                                max_loss = position['highest_price'] - position['open_price']

                                # 计算盈亏比（盈利/亏损的比值，避免除零）
                                # v0.3.0修复：避免Infinity，改用大数值9999.99
                                if max_loss > 0:
                                    profit_ratio = round(abs(max_profit / max_loss), 2)
                                else:
                                    profit_ratio = 9999.99 if max_profit > 0 else 0

                                # 判断离场原因（基于最终盈亏方向）
                                exit_reason = "止盈" if profit > 0 else "止损"

                                period = self._format_period(
                                    position['open_time'],
                                    position['close_time']
                                )

                                trades.append({
                                    'action': 'short',  # 记录为short表示空头交易
                                    'position_type': 'short',
                                    'period': period,
                                    'profit': round(profit, 2),
                                    'openPrice': position['open_price'],
                                    'closePrice': position['close_price'],
                                    'exitReason': exit_reason,  # 离场原因
                                    'profitRatio': profit_ratio  # 盈亏比
                                })

                                position = None  # 清空持仓
                        # short/hold时继续持有

            # Bugfix v0.3.5: 统一记录analyses，确保每次循环只记录一次，避免重复数据
            # Bugfix v0.3.4: 如果触发止盈止损，平仓时action应设为close而非hold
            final_action = action
            if should_close_by_ai_price:
                final_action = 'close'

            # Bugfix v0.3.5: 统一在这里记录analyses，确保每次循环只记录一次
            # 检查AI分析是否成功，如果不成功则设置异常reason
            if result['code'] != 200:
                reason = f'分析异常: {result.get("msg", "未知错误")} (code={result.get("code", "N/A")})'
                # 清空相关字段
                action = 'hold'
                stop_loss = None
                take_profit = None
                measure_move = None
                breakout_price = None
                support_resistance_level = None
                final_action = action
            print(f"[DEBUG v0.3.5] 记录analyses, index={i}, action={final_action}, reason={reason[:50]}...")
            analyses.append({
            'index': i,
            'time': current_time.strftime('%Y-%m-%d %H:%M:%S'),
            'kline_time': kline_time,
            'action': final_action,  # 使用最终action，而非原始AI分析action
            'reason': reason,
            'price': current_kline['close'],
            'stopLoss': stop_loss,
            'takeProfit': take_profit,
            'measureMove': measure_move,
            'breakoutPrice': breakout_price,  # v0.2.9: 突破价格
            'supportResistanceLevel': support_resistance_level,  # v0.2.9: 支撑/阻力位价格
            'aiOpenPrice': ai_open_price,
            'aiClosePrice': ai_close_price
        })

        # 处理未平仓的最后一个位置（支持做空）
        if position is not None:
            # 在回测结束时强制平仓
            last_kline = klines[-1]
            # Bugfix v0.3.5: 使用last_kline的close_time确保period时间范围正确（开仓用open_time，平仓用close_time）
            position['close_time'] = last_kline['close_time']
            position['close_price'] = last_kline['close']
            position['close_index'] = len(klines) - 1

            # 根据持仓类型计算盈亏
            current_position_type = position.get('position_type', 'long')
            if current_position_type == 'long':
                # 多头：平仓价 - 开仓价
                profit = position['close_price'] - position['open_price']
                action = 'long'

                # 计算最大盈利和最大亏损
                max_profit = position['highest_price'] - position['open_price']
                max_loss = position['open_price'] - position['lowest_price']
            else:
                # 空头：开仓价 - 平仓价
                profit = position['open_price'] - position['close_price']
                action = 'short'

                # 计算最大盈利和最大亏损（做空相反）
                max_profit = position['open_price'] - position['lowest_price']
                max_loss = position['highest_price'] - position['open_price']

            # 计算盈亏比（盈利/亏损的比值，避免除零）
            # v0.3.0修复：避免Infinity，改用大数值9999.99
            if max_loss > 0:
                profit_ratio = round(abs(max_profit / max_loss), 2)
            else:
                profit_ratio = 9999.99 if max_profit > 0 else 0

            # 判断离场原因（强制平仓，视为时间止损）
            exit_reason = "时间止损" if profit < 0 else "时间止盈"

            period = self._format_period(
                position['open_time'],
                position['close_time']
            )

            trades.append({
                'action': action,
                'position_type': current_position_type,
                'period': period,
                'profit': round(profit, 2),
                'openPrice': position['open_price'],
                'closePrice': position['close_price'],
                'exitReason': exit_reason,  # 离场原因
                'profitRatio': profit_ratio  # 盈亏比
            })

        return trades, analysis_count, analyses

    def _format_period(self, start_time: int, end_time: int) -> str:
        """
        格式化交易周期

        Args:
            start_time: 开始时间戳
            end_time: 结束时间戳

        Returns:
            格式化的时间周期字符串
        """
        start_dt = datetime.fromtimestamp(start_time / 1000)
        end_dt = datetime.fromtimestamp(end_time / 1000)

        return f"{start_dt.strftime('%Y-%m-%d %H:%M')} - {end_dt.strftime('%Y-%m-%d %H:%M')}"
